package com.lagou.task;

import com.lagou.util.RedisUtil;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author bobcheng
 * @date 2020/6/16
 */
public class TPMonitorTask implements Runnable {

    private TPMonitorTask() {}

    private static final String BIZ_CODE = "TPMonitor";

    private static TPMonitorTask instance;

    static {
        instance = new TPMonitorTask();
    }

    public static TPMonitorTask getInstance() {
        return instance;
    }

    @Override
    public void run() {
        System.out.println("monitor start");
        Set<String> keys = RedisUtil.keys(BIZ_CODE + "*");
        if (CollectionUtils.isEmpty(keys)) {
            return;
        }
        Map<String, List<String>> monitors = keys.stream().collect(Collectors.groupingBy(k -> {
            String[] arr = k.split("_");
            String serviceName = arr[1];
            String methodName = arr[2];
            return serviceName + "_" + methodName;
        }));
        monitors.forEach((group, groupKeys) -> {
            List<Long> sortedCostTimes = groupKeys.stream().map(k -> Long.parseLong(RedisUtil.get(k))).sorted().collect(Collectors.toList());
            Long tp90 = calculateTP90(sortedCostTimes);
            Long tp99 = calculateTP99(sortedCostTimes);
            System.out.println(group + "最近1分钟内TP90的耗时情况:" + tp90 + "ms");
            System.out.println(group + "最近1分钟内TP99的耗时情况:" + tp99 + "ms");
        });
    }

    public static void saveCost(long costTime, String serviceName, String methodName) {
        Long id = RedisUtil.getIncrId();
        String key = String.format("%s_%s_%s_%d", BIZ_CODE, serviceName, methodName, id);
        RedisUtil.set(key, String.valueOf(costTime), 60);
    }

    private Long calculateTP90(List<Long> sortedCostTimes) {
        return calculateTP(sortedCostTimes, 90);
    }

    private Long calculateTP99(List<Long> sortedCostTimes) {
        return calculateTP(sortedCostTimes, 99);
    }

    private Long calculateTP(List<Long> sortedCostTimes, int percentile) {
        int size = sortedCostTimes.size();
        int i = size * percentile;
        int site = (i % 100) == 0 ? i / 100 : (i / 100) + 1;
        return sortedCostTimes.get(site - 1);
    }
}
